/*---------------------------------------------------------------------
 * File name: hal_uart.cpp
 *
 * Copyright (c) <2020-2022>, <ChenLong>
 *
 * All rights reserved.
 *
 * Author: ChenLong
 * Email: worldlong@foxmail.com
 *--------------------------------------------------------------------*/
#include "gd32f10x.h"
#include "buffer/simple_buffer.h"
#include "hal_uart.h"
#include "hal_config.h"
#if defined(USING_RT_THREAD)
#include "rtthread.h" 
#endif
/*
*/
static void (*rx_irq_hook[5])(void *param, uint32_t flag) = {nullptr};
static void *rx_irq_hook_param[5]={nullptr};
static void (*tx_irq_hook[5])(void *param, uint32_t flag) = {nullptr};
static void *tx_irq_hook_param[5]={nullptr};
//UART0 
#if UART0_ENABLE
#if UART0_RX_DMA_ENABLE
#if UART0_RX_DMA == DMA0_CHANNEL4
#define UART0_RX_DMA_PORT DMA0
#define UART0_RX_DMA_CH   DMA_CH4
#else
#error "UART0_RX_DMA incorrect."
#endif
#else
#define UART0_RX_DMA_PORT 0
#define UART0_RX_DMA_CH   0
#endif

#if UART0_TX_DMA_ENABLE
#if UART0_TX_DMA == DMA0_CHANNEL3
#define UART0_TX_DMA_PORT    DMA0
#define UART0_TX_DMA_CH      DMA_CH3
#define UART0_TX_DMA_CH_IRQN DMA0_Channel3_IRQn
#define UART0_TX_DMA_CH_IRQH DMA0_Channel3_IRQHandler
#else
#error "UART0_TX_DMA incorrect."
#endif
#else
#define UART0_TX_DMA_PORT 0
#define UART0_TX_DMA_CH   0
#endif
#endif
//UART1 
#if UART1_ENABLE
#if UART1_RX_DMA_ENABLE
#if UART1_RX_DMA == DMA0_CHANNEL5
#define UART1_RX_DMA_PORT DMA0
#define UART1_RX_DMA_CH   DMA_CH5
#else
#error "UART1_RX_DMA incorrect."
#endif
#else
#define UART1_RX_DMA_PORT 0
#define UART1_RX_DMA_CH   0
#endif

#if UART1_TX_DMA_ENABLE
#if UART1_TX_DMA == DMA0_CHANNEL6
#define UART1_TX_DMA_PORT    DMA0
#define UART1_TX_DMA_CH      DMA_CH6
#define UART1_TX_DMA_CH_IRQN DMA0_Channel6_IRQn
#define UART1_TX_DMA_CH_IRQH DMA0_Channel6_IRQHandler
#else
#error "UART1_TX_DMA incorrect."
#endif
#else
#define UART1_TX_DMA_PORT 0
#define UART1_TX_DMA_CH   0
#endif
#endif
//UART2 
#if UART2_ENABLE
#if UART2_RX_DMA_ENABLE
#if UART2_RX_DMA == DMA0_CHANNEL2
#define UART2_RX_DMA_PORT DMA0
#define UART2_RX_DMA_CH   DMA_CH2
#else
#error "UART2_RX_DMA incorrect."
#endif
#else
#define UART2_RX_DMA_PORT 0
#define UART2_RX_DMA_CH   0
#endif

#if UART2_TX_DMA_ENABLE
#if UART2_TX_DMA == DMA0_CHANNEL1
#define UART2_TX_DMA_PORT    DMA0
#define UART2_TX_DMA_CH      DMA_CH1
#define UART2_TX_DMA_CH_IRQN DMA0_Channel1_IRQn
#define UART2_TX_DMA_CH_IRQH DMA0_Channel1_IRQHandler
#else
#error "UART2_TX_DMA incorrect."
#endif
#else
#define UART2_TX_DMA_PORT 0
#define UART2_TX_DMA_CH   0
#endif
#endif
//UART3 
#if UART3_ENABLE
#if UART3_RX_DMA_ENABLE
#if UART3_RX_DMA == DMA1_CHANNEL2
#define UART3_RX_DMA_PORT DMA1
#define UART3_RX_DMA_CH   DMA_CH2
#else
#error "UART3_RX_DMA incorrect."
#endif
#else
#define UART3_RX_DMA_PORT 0
#define UART3_RX_DMA_CH   0
#endif

#if UART3_TX_DMA_ENABLE
#if UART3_TX_DMA == DMA1_CHANNEL4
#define UART3_TX_DMA_PORT    DMA1
#define UART3_TX_DMA_CH      DMA_CH4
#define UART3_TX_DMA_CH_IRQN DMA1_Channel4_IRQn
#define UART3_TX_DMA_CH_IRQH DMA1_Channel4_IRQHandler
#else
#error "UART3_TX_DMA incorrect."
#endif
#else
#define UART3_TX_DMA_PORT 0
#define UART3_TX_DMA_CH   0
#endif
#endif
//UART4
#if UART4_ENABLE
#if UART4_RX_DMA_ENABLE || UART4_TX_DMA_ENABLE
#error "UART4 dosen't have DMA."
#endif
#endif

/*---------------------------------------------------
 *                   UART_Object
 *---------------------------------------------------*/
class UART_Object
{
public:
  UART_Object(uint32_t USARTx,
              uint32_t RDMA,
              dma_channel_enum RDMA_CH, 
              uint32_t TDMA,
              dma_channel_enum TDMA_CH,
              uint8_t *dma_rx_buffer, int dma_rx_buffer_size,
              uint8_t *dma_tx_buffer, int dma_tx_buffer_size,
              SimpleBuffer<uint8_t> &rx_buffer,
              SimpleBuffer<uint8_t> &tx_buffer) :
    uart(USARTx),
    rx_dma(RDMA),
    tx_dma(TDMA),
    rx_dma_ch(RDMA_CH),
    tx_dma_ch(TDMA_CH),
    dma_rx_buffer(dma_rx_buffer),
    dma_tx_buffer(dma_tx_buffer),
    dma_rx_buffer_size(dma_rx_buffer_size),
    dma_tx_buffer_size(dma_tx_buffer_size),
    rx_buffer(rx_buffer),
    tx_buffer(tx_buffer),
    rx_busy(false),
    tx_busy(false)
  {}
  
  uint32_t uart;
  uint32_t rx_dma;
  uint32_t tx_dma;
  dma_channel_enum rx_dma_ch;
  dma_channel_enum tx_dma_ch;
  uint8_t *dma_rx_buffer;
  uint8_t *dma_tx_buffer;
  int dma_rx_buffer_size;
  int dma_tx_buffer_size;
  SimpleBuffer<uint8_t> &rx_buffer;
  SimpleBuffer<uint8_t> &tx_buffer;
  bool rx_busy;
  bool tx_busy;
  
  void dma_rx_config();
  void dma_rx_start();
  void dma_rx_end(bool error);
  void dma_tx_config();
  void dma_tx_start();
  void dma_tx_end();
  void int_rx_config();
  void int_tx_config();
  void int_rx(bool error);
  int int_tx();
  void send();
  bool config(uint32_t cfg);
};
/*
*/
void UART_Object::dma_rx_config()
{
  dma_parameter_struct dma_init_struct;
  
  dma_deinit(rx_dma, rx_dma_ch);
  dma_struct_para_init(&dma_init_struct);
  dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
  dma_init_struct.memory_addr = (uint32_t)dma_rx_buffer;
  dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
  dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
  dma_init_struct.number = dma_rx_buffer_size;
  dma_init_struct.periph_addr = ((uint32_t)&USART_DATA(uart));
  dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
  dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
  dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
  dma_init(rx_dma, rx_dma_ch, &dma_init_struct);
  
  dma_circulation_disable(rx_dma, rx_dma_ch);
  dma_memory_to_memory_disable(rx_dma, rx_dma_ch);
  
  //Interrupt config
  usart_interrupt_enable(uart, USART_INT_IDLE);  
  //Enable usart dma receive      
  usart_dma_receive_config(uart, USART_DENR_ENABLE);
  
  dma_channel_enable(rx_dma, rx_dma_ch);
}
/*
*/
void UART_Object::dma_tx_config()
{
  dma_parameter_struct dma_init_struct;
  
  dma_deinit(tx_dma, tx_dma_ch);
  dma_struct_para_init(&dma_init_struct);
  dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
  dma_init_struct.memory_addr = (uint32_t)dma_tx_buffer;
  dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
  dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
  dma_init_struct.number = 0;
  dma_init_struct.periph_addr = ((uint32_t)&USART_DATA(uart));
  dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
  dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
  dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
  dma_init(tx_dma, tx_dma_ch, &dma_init_struct);
  
  dma_circulation_disable(tx_dma, tx_dma_ch);
  dma_memory_to_memory_disable(tx_dma, tx_dma_ch);
  
  //Interrupt config
  dma_interrupt_enable(tx_dma, tx_dma_ch, DMA_INT_FTF);
  //Enable usart dma transmit
  usart_dma_transmit_config(uart, USART_DENT_ENABLE);
  
  dma_channel_disable(tx_dma, tx_dma_ch);  //disable first
}
/*
*/
void UART_Object::dma_tx_start()
{
  if(!tx_busy)
  {
    int number = tx_buffer.pop(dma_tx_buffer, dma_tx_buffer_size);
    if(number > 0)
    {
      tx_busy = true;
      dma_transfer_number_config(tx_dma, tx_dma_ch, number);
      dma_channel_enable(tx_dma, tx_dma_ch);
    }
  }
}
/*
*/
void UART_Object::dma_tx_end()
{
  dma_channel_disable(tx_dma, tx_dma_ch);
  tx_busy = false;
}
/*
*/
void UART_Object::dma_rx_start()
{
  if(!rx_busy)
  {
    rx_busy = true;
    dma_transfer_number_config(rx_dma, rx_dma_ch, dma_rx_buffer_size);
    dma_channel_enable(rx_dma, rx_dma_ch);
  }
}
/*
*/
void UART_Object::dma_rx_end(bool error)
{
  dma_channel_disable(rx_dma, rx_dma_ch);
  if(!error) { //no error
    int number = dma_rx_buffer_size - dma_transfer_number_get(rx_dma, rx_dma_ch);
    rx_buffer.push(dma_rx_buffer, number);
  }
  rx_busy = false;
}
/*
*/
void UART_Object::int_rx_config()
{
  //Disable usart dma receive      
  usart_dma_receive_config(uart, USART_DENR_DISABLE);
  //Interrupt config
  usart_interrupt_flag_clear(uart, USART_INT_FLAG_RBNE);
  usart_interrupt_flag_clear(uart, USART_INT_IDLE);
  usart_interrupt_enable(uart, USART_INT_RBNE);  
  usart_interrupt_enable(uart, USART_INT_IDLE);
}
/*
*/
void UART_Object::int_tx_config()
{
  //Disable usart dma transmit
  usart_dma_transmit_config(uart, USART_DENT_DISABLE);
  //Interrupt config
  usart_interrupt_disable(uart, USART_INT_TBE);
}
/*
*/
void UART_Object::int_rx(bool error)
{
  uint8_t data = usart_data_receive(uart);
  if(!error) {
    rx_buffer.push(&data, 1);
  }
}
/*
*/
int UART_Object::int_tx()
{
  uint8_t data;
  
  int number = tx_buffer.pop(&data, 1);
  
  if(number > 0) {
    usart_data_transmit(uart, data);
  } else {
    usart_interrupt_disable(uart, USART_INT_TBE); 
  }
  return number;
}
/*
*/
void UART_Object::send()
{
  if(dma_tx_buffer != nullptr) {
    dma_tx_start();
  } else {
    usart_interrupt_enable(uart, USART_INT_TBE);  //just enable interrupt
  }
}
/*
*/
bool UART_Object::config(uint32_t cfg)
{
  //baud
  uint32_t tmp = HUART_CFG_EXTRACT(cfg, BAUD);
  usart_baudrate_set(uart, tmp);
  //data bits
  tmp = HUART_CFG_EXTRACT(cfg, DATA);
  if(tmp == HUART_DATA(8B)) {
    usart_word_length_set(uart, USART_WL_8BIT);
  } else if (tmp == HUART_DATA(9B)) {
    usart_word_length_set(uart, USART_WL_9BIT);
  } else {
    return false;
  }
  //parity
  tmp = HUART_CFG_EXTRACT(cfg, PARITY);
  if(tmp == HUART_PARITY(NONE)) {
    usart_parity_config(uart, USART_PM_NONE);
  } else if(tmp == HUART_PARITY(ODD)) {
    usart_parity_config(uart, USART_PM_ODD);
  } else if(tmp == HUART_PARITY(EVEN)) {
    usart_parity_config(uart, USART_PM_EVEN);
  } else {
    return false;
  }
  //stop bits
  tmp = HUART_CFG_EXTRACT(cfg, STOP);
  if(tmp == HUART_STOP(0B5)) {
    usart_stop_bit_set(uart, USART_STB_0_5BIT);  
  } else if(tmp == HUART_STOP(1B)) {
    usart_stop_bit_set(uart, USART_STB_1BIT);   
  } else if(tmp == HUART_STOP(1B5)) {
    usart_stop_bit_set(uart, USART_STB_1_5BIT);   
  } else if(tmp == HUART_STOP(2B)) {
    usart_stop_bit_set(uart, USART_STB_2BIT); 
  } else {
    return false;
  }
  usart_receive_config(uart, USART_RECEIVE_ENABLE);
  usart_transmit_config(uart, USART_TRANSMIT_ENABLE);
  usart_enable(uart);
  return true;
}
/*----------------------------------------
 *             UART0 Object
 *-----------------------------------------*/
#if UART0_ENABLE
#if UART0_RX_DMA_ENABLE
  static uint8_t uart0_rx_dma_buffer[UART0_RX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart0_rx_dma_buffer = nullptr;
#endif
#if UART0_TX_DMA_ENABLE
  static uint8_t uart0_tx_dma_buffer[UART0_TX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart0_tx_dma_buffer = nullptr;
#endif
  static uint8_t uart0_rx_buffer[UART0_RX_BUFFER_SIZE];
  static uint8_t uart0_tx_buffer[UART0_TX_BUFFER_SIZE];
  static SimpleBuffer<uint8_t> uart0_rx_sbuffer(uart0_rx_buffer, UART0_RX_BUFFER_SIZE);
  static SimpleBuffer<uint8_t> uart0_tx_sbuffer(uart0_tx_buffer, UART0_TX_BUFFER_SIZE);
  static UART_Object uart0(USART0, 
                           UART0_RX_DMA_PORT, (dma_channel_enum)UART0_RX_DMA_CH, 
                           UART0_TX_DMA_PORT, (dma_channel_enum)UART0_TX_DMA_CH,
                           uart0_rx_dma_buffer, UART0_RX_DMA_BUFFER_SIZE,
                           uart0_tx_dma_buffer, UART0_TX_DMA_BUFFER_SIZE,
                           uart0_rx_sbuffer,
                           uart0_tx_sbuffer);
#endif
/*----------------------------------------
 *             UART1 Object
 *-----------------------------------------*/
#if UART1_ENABLE
#if UART1_RX_DMA_ENABLE
  static uint8_t uart1_rx_dma_buffer[UART1_RX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart1_rx_dma_buffer = nullptr;
#endif
#if UART1_TX_DMA_ENABLE
  static uint8_t uart1_tx_dma_buffer[UART1_TX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart1_tx_dma_buffer = nullptr;
#endif
  static uint8_t uart1_rx_buffer[UART1_RX_BUFFER_SIZE];
  static uint8_t uart1_tx_buffer[UART1_TX_BUFFER_SIZE];
  static SimpleBuffer<uint8_t> uart1_rx_sbuffer(uart1_rx_buffer, UART1_RX_BUFFER_SIZE);
  static SimpleBuffer<uint8_t> uart1_tx_sbuffer(uart1_tx_buffer, UART1_TX_BUFFER_SIZE);
  static UART_Object uart1(USART1, 
                           UART1_RX_DMA_PORT, (dma_channel_enum)UART1_RX_DMA_CH, 
                           UART1_TX_DMA_PORT, (dma_channel_enum)UART1_TX_DMA_CH,
                           uart1_rx_dma_buffer, UART1_RX_DMA_BUFFER_SIZE,
                           uart1_tx_dma_buffer, UART1_TX_DMA_BUFFER_SIZE,
                           uart1_rx_sbuffer,
                           uart1_tx_sbuffer);
#endif
/*----------------------------------------
 *             UART2 Object
 *-----------------------------------------*/
#if UART2_ENABLE
#if UART2_RX_DMA_ENABLE
  static uint8_t uart2_rx_dma_buffer[UART2_RX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart2_rx_dma_buffer = nullptr;
#endif
#if UART2_TX_DMA_ENABLE
  static uint8_t uart2_tx_dma_buffer[UART2_TX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart2_tx_dma_buffer = nullptr;
#endif
  static uint8_t uart2_rx_buffer[UART2_RX_BUFFER_SIZE];
  static uint8_t uart2_tx_buffer[UART2_TX_BUFFER_SIZE];
  static SimpleBuffer<uint8_t> uart2_rx_sbuffer(uart2_rx_buffer, UART2_RX_BUFFER_SIZE);
  static SimpleBuffer<uint8_t> uart2_tx_sbuffer(uart2_tx_buffer, UART2_TX_BUFFER_SIZE);
  static UART_Object uart2(USART2, 
                           UART2_RX_DMA_PORT, (dma_channel_enum)UART2_RX_DMA_CH, 
                           UART2_TX_DMA_PORT, (dma_channel_enum)UART2_TX_DMA_CH,
                           uart2_rx_dma_buffer, UART2_RX_DMA_BUFFER_SIZE,
                           uart2_tx_dma_buffer, UART2_TX_DMA_BUFFER_SIZE,
                           uart2_rx_sbuffer,
                           uart2_tx_sbuffer);
#endif
/*----------------------------------------
 *             UART3 Object
 *-----------------------------------------*/
#if UART3_ENABLE
#if UART3_RX_DMA_ENABLE
  static uint8_t uart3_rx_dma_buffer[UART3_RX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart3_rx_dma_buffer = nullptr;
#endif
#if UART3_TX_DMA_ENABLE
  static uint8_t uart3_tx_dma_buffer[UART3_TX_DMA_BUFFER_SIZE];
#else
  static uint8_t *uart3_tx_dma_buffer = nullptr;
#endif
  static uint8_t uart3_rx_buffer[UART3_RX_BUFFER_SIZE];
  static uint8_t uart3_tx_buffer[UART3_TX_BUFFER_SIZE];
  static SimpleBuffer<uint8_t> uart3_rx_sbuffer(uart3_rx_buffer, UART3_RX_BUFFER_SIZE);
  static SimpleBuffer<uint8_t> uart3_tx_sbuffer(uart3_tx_buffer, UART3_TX_BUFFER_SIZE);
  static UART_Object uart3(UART3, 
                           UART3_RX_DMA_PORT, (dma_channel_enum)UART3_RX_DMA_CH, 
                           UART3_TX_DMA_PORT, (dma_channel_enum)UART3_TX_DMA_CH,
                           uart3_rx_dma_buffer, UART3_RX_DMA_BUFFER_SIZE,
                           uart3_tx_dma_buffer, UART3_TX_DMA_BUFFER_SIZE,
                           uart3_rx_sbuffer,
                           uart3_tx_sbuffer);
#endif
/*----------------------------------------
 *             UART4 Object
 *-----------------------------------------*/
#if UART4_ENABLE
  static uint8_t uart4_rx_buffer[UART4_RX_BUFFER_SIZE];
  static uint8_t uart4_tx_buffer[UART4_TX_BUFFER_SIZE];
  static SimpleBuffer<uint8_t> uart4_rx_sbuffer(uart4_rx_buffer, UART4_RX_BUFFER_SIZE);
  static SimpleBuffer<uint8_t> uart4_tx_sbuffer(uart4_tx_buffer, UART4_TX_BUFFER_SIZE);
  static UART_Object uart4(UART4, 
                           0, (dma_channel_enum)0, 
                           0, (dma_channel_enum)0,
                           nullptr, 0,
                           nullptr, 0,
                           uart4_rx_sbuffer,
                           uart4_tx_sbuffer);
#endif
  
  
/**********************************
 *         HAL_UART
 **********************************/
bool HAL_UART::init(uint32_t cfg0)
{
  uint8_t rx_nvic_irqn = 0;
  uint8_t tx_nvic_irqn = 0;
  uint8_t nvic_prio = 0;
  
  cfg = cfg0;
  uint32_t tmp = HUART_CFG_EXTRACT(cfg, PORT);
  if(tmp == 0) {  //No port
   return false;
  }
 //UART0
#if UART0_ENABLE
  else if(tmp == HUART_PORT(0)) {
    port = (uint32_t)&uart0;
    nvic_prio = NVIC_IRQ_UART0_PRIORITY;
    rx_nvic_irqn = USART0_IRQn;
    _index = 0;
    //Rx
#if UART0_RX_DMA_ENABLE
    uart0.dma_rx_config();
#else
    uart0.int_rx_config();
#endif
    //Tx
#if UART0_TX_DMA_ENABLE
    uart0.dma_tx_config();
    tx_nvic_irqn = UART0_TX_DMA_CH_IRQN;
#else
    uart0.int_tx_config();  //Not DMA mode, just keep tx_nvic_irqn = 0, because it's same to rx_nvic_irqn
#endif
  }
#endif
  //UART1
#if UART1_ENABLE
  else if(tmp == HUART_PORT(1)) {
    port = (uint32_t)&uart1;
    nvic_prio = NVIC_IRQ_UART1_PRIORITY;
    rx_nvic_irqn = USART1_IRQn;
    _index = 1;
    //Rx
#if UART1_RX_DMA_ENABLE
    uart1.dma_rx_config();
#else
    uart1.int_rx_config();
#endif
    //Tx
#if UART1_TX_DMA_ENABLE
    uart1.dma_tx_config();
    tx_nvic_irqn = UART1_TX_DMA_CH_IRQN;
#else
    uart1.int_tx_config();  //Not DMA mode, just keep tx_nvic_irqn = 0, because it's same to rx_nvic_irqn
#endif
  }
#endif
    //UART2
#if UART2_ENABLE
  else if(tmp == HUART_PORT(2)) {
    port = (uint32_t)&uart2;
    nvic_prio = NVIC_IRQ_UART2_PRIORITY;
    rx_nvic_irqn = USART2_IRQn;
    _index = 2;
    //Rx
#if UART2_RX_DMA_ENABLE
    uart2.dma_rx_config();
#else
    uart2.int_rx_config();
#endif
    //Tx
#if UART2_TX_DMA_ENABLE
    uart2.dma_tx_config();
    tx_nvic_irqn = UART2_TX_DMA_CH_IRQN;
#else
    uart2.int_tx_config();
#endif
  }
#endif
    //UART3
#if UART3_ENABLE
  else if(tmp == HUART_PORT(3)) {
    port = (uint32_t)&uart3;
    nvic_prio = NVIC_IRQ_UART3_PRIORITY;
    rx_nvic_irqn = UART3_IRQn;
    _index = 3;
    //Rx
#if UART3_RX_DMA_ENABLE
    uart3.dma_rx_config();
#else
    uart3.int_rx_config();
#endif
    //Tx
#if UART3_TX_DMA_ENABLE
    uart3.dma_tx_config();
    tx_nvic_irqn = UART3_TX_DMA_CH_IRQN;
#else
    uart3.int_tx_config();
#endif
  }
#endif
    //UART4
#if UART4_ENABLE
  else if(tmp == HUART_PORT(4)) {
    port = (uint32_t)&uart4;
    nvic_prio = NVIC_IRQ_UART4_PRIORITY;
    rx_nvic_irqn = UART4_IRQn;
    _index = 4;
    //Rx
#if UART4_RX_DMA_ENABLE
    uart4.dma_rx_config();
#else
    uart4.int_rx_config();
#endif
    //Tx
#if UART4_TX_DMA_ENABLE
    uart4.dma_tx_config();
    tx_nvic_irqn = UART4_TX_DMA_CH_IRQN;
#else
    uart4.int_tx_config();
#endif
  }
#endif
  else {
    return false;
  }
  
  if(!config(cfg)) {
    return false;
  }
  
  //NVIC config
  //rx
  if(rx_nvic_irqn > 0) {
    nvic_irq_enable(rx_nvic_irqn, nvic_prio, 0U);
  }
  //tx
  if(tx_nvic_irqn > 0) {
    nvic_irq_enable(tx_nvic_irqn, nvic_prio, 0U);
  }
  return true;
}
/*
*/
bool HAL_UART::config(uint32_t cfg0)
{
  cfg &= ~HUART_CFG_MASK;
  cfg |= cfg0 & HUART_CFG_MASK;
  return ((UART_Object*)port)->config(cfg);
}
/*
*/
int HAL_UART::read(uint8_t *buffer, uint32_t num)
{
  return ((UART_Object*)port)->rx_buffer.pop(buffer, num);
}
/*
*/
int HAL_UART::write(uint8_t *buffer, uint32_t num)
{
  int ret = ((UART_Object*)port)->tx_buffer.push(buffer, num);
  ((UART_Object*)port)->send();
  return ret;
}
/*
*/
int HAL_UART::write(uint8_t *buffer, uint32_t num, uint32_t ms)
{
  while(((UART_Object*)port)->tx_buffer.full_check(num)) {
#if defined(USING_RT_THREAD)
  rt_thread_mdelay(ms);
#endif
  }
  int ret = ((UART_Object*)port)->tx_buffer.push(buffer, num);
  ((UART_Object*)port)->send();
  return ret;
}
/*
*/
int HAL_UART::write_block(uint8_t *buffer, uint32_t num)
{
  for(int i=0; i< num; i++) {
    while(usart_flag_get(((UART_Object*)port)->uart, USART_FLAG_TBE) == RESET);
    usart_data_transmit(((UART_Object*)port)->uart, buffer[i]);
  }
  return num;
}
/*
*/
int HAL_UART::rx_buffer_number()
{
  return ((UART_Object*)port)->rx_buffer.number();
}
/*
*/
int HAL_UART::tx_buffer_number()
{
  return ((UART_Object*)port)->tx_buffer.number();
}
/*
*/
void HAL_UART::flush()
{
  ((UART_Object*)port)->rx_buffer.flush();
}
/*
*/
void HAL_UART::attach_rx_irq(void(*fun)(void *param, uint32_t flag), void *param)
{
  rx_irq_hook[_index] = fun;
  rx_irq_hook_param[_index] = param;
  if(rx_irq_hook[0]) {}        //just use to remove the Warning[Pe550]
  if(rx_irq_hook_param[0]) {}  //just use to remove the Warning[Pe550]
}
/*
*/
void HAL_UART::attach_tx_irq(void(*fun)(void *param, uint32_t flag), void *param)
{
  tx_irq_hook[_index] = fun;
  tx_irq_hook_param[_index] = param;
  if(tx_irq_hook[0]) {}        //just use to remove the Warning[Pe550]
  if(tx_irq_hook_param[0]) {}  //just use to remove the Warning[Pe550]
}
/*------------------------------------------------
 *             IRQHandler
 *------------------------------------------------*/
#ifdef __cplusplus
 extern "C" {
#endif
/*
*/
#if UART0_ENABLE
void USART0_IRQHandler()
{ 
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  uint32_t int_status = USART_STAT(USART0);
  usart_data_receive(USART0); //clear flag
  bool error = int_status & 0x07; //NERR, FERR or PERR
  if(error) {  //for debug
    error = 1;
  }
 if((int_status & 0x10)) { //IDLE interrupt for Rx end
    //DMA Rx
#if UART0_RX_DMA_ENABLE  
    uart0.dma_rx_end(error);  
    uart0.dma_rx_start();
#endif
    if(rx_irq_hook[0] != nullptr) {
      rx_irq_hook[0](rx_irq_hook_param[0], error);
    }
  }
  
  //Int Rx
#if !UART0_RX_DMA_ENABLE
  if((int_status & 0x20)) { //RBNE interrupt
    uart0.int_rx(error);
  }
#endif
  
  //Int Tx
#if !UART0_TX_DMA_ENABLE
  if((int_status & 0x80)) //TBE
  {
    if(uart0.int_tx() == 0) { //Tx end
      if(tx_irq_hook[0] != nullptr) {
        tx_irq_hook[0](tx_irq_hook_param[0], 0);
      }
    }
  }
#endif
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
/*
*/
#if UART0_TX_DMA_ENABLE
void UART0_TX_DMA_CH_IRQH()
{
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  if(dma_interrupt_flag_get(UART0_TX_DMA_PORT, UART0_TX_DMA_CH, DMA_INT_FLAG_FTF) != RESET)
  {
    dma_interrupt_flag_clear(UART0_TX_DMA_PORT, UART0_TX_DMA_CH, DMA_INT_FLAG_FTF);
    if(tx_irq_hook[0] != nullptr) {
      tx_irq_hook[0](tx_irq_hook_param[0], 0);
    }
    uart0.dma_tx_end();
    uart0.dma_tx_start();
  }
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
#endif
#endif
/*
*/
#if UART1_ENABLE
void USART1_IRQHandler()
{ 
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  uint32_t int_status = USART_STAT(USART1);
  usart_data_receive(USART1); //clear flag
  bool error = int_status & 0x07; //NERR, FERR or PERR
  
 if((int_status & 0x10)) { //IDLE interrupt for Rx end
    //DMA Rx
#if UART1_RX_DMA_ENABLE  
    uart1.dma_rx_end(error);  
    uart1.dma_rx_start();
#endif
    if(rx_irq_hook[1] != nullptr) {
      rx_irq_hook[1](rx_irq_hook_param[1], error);
    }
  }
  
  //Int Rx
#if !UART1_RX_DMA_ENABLE
  if((int_status & 0x20)) { //RBNE interrupt
    uart1.int_rx(error);
  }
#endif
  
  //Int Tx
#if !UART1_TX_DMA_ENABLE
  if((int_status & 0x80)) //TBE
  {
    if(uart1.int_tx() == 0) { //Tx end
      if(tx_irq_hook[1] != nullptr) {
        tx_irq_hook[1](tx_irq_hook_param[1], 0);
      }
    }
  }
#endif
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
/*
*/
#if UART1_TX_DMA_ENABLE
void UART1_TX_DMA_CH_IRQH()
{
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  if(dma_interrupt_flag_get(UART1_TX_DMA_PORT, UART1_TX_DMA_CH, DMA_INT_FLAG_FTF) != RESET)
  {
    dma_interrupt_flag_clear(UART1_TX_DMA_PORT, UART1_TX_DMA_CH, DMA_INT_FLAG_FTF);
    if(tx_irq_hook[1] != nullptr) {
      tx_irq_hook[1](tx_irq_hook_param[1], 0);
    }
    uart1.dma_tx_end();
    uart1.dma_tx_start();
  }
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
#endif
#endif
/*
*/
#if UART2_ENABLE
void USART2_IRQHandler()
{ 
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  uint32_t int_status = USART_STAT(USART2);
  usart_data_receive(USART2); //clear flag
  bool error = int_status & 0x07; //NERR, FERR or PERR
  if(error) {  //for debug
    error = 1;
  }
  
  if((int_status & 0x10)) { //IDLE interrupt for Rx end
    //DMA Rx
#if UART2_RX_DMA_ENABLE  
    uart2.dma_rx_end(error);  
    uart2.dma_rx_start();
#endif
    if(rx_irq_hook[2] != nullptr) {
      rx_irq_hook[2](rx_irq_hook_param[2], error);
    }
  }
  
  //Int Rx
#if !UART2_RX_DMA_ENABLE
  if((int_status & 0x20)) { //RBNE interrupt
    uart2.int_rx(error);
  }
#endif
  
  //Int Tx
#if !UART2_TX_DMA_ENABLE
  if((int_status & 0x80)) //TBE
  {
    if(uart2.int_tx() == 0) { //Tx end
      if(tx_irq_hook[2] != nullptr) {
        tx_irq_hook[2](tx_irq_hook_param[2], 0);
      }
    }
  }
#endif
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
/*
*/
#if UART2_TX_DMA_ENABLE
void UART2_TX_DMA_CH_IRQH()
{
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  if(dma_interrupt_flag_get(UART2_TX_DMA_PORT, UART2_TX_DMA_CH, DMA_INT_FLAG_FTF) != RESET)
  {
    dma_interrupt_flag_clear(UART2_TX_DMA_PORT, UART2_TX_DMA_CH, DMA_INT_FLAG_FTF);
    if(tx_irq_hook[2] != nullptr) {
      tx_irq_hook[2](tx_irq_hook_param[2], 0);
    }
    uart2.dma_tx_end();
    uart2.dma_tx_start();
  }
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
#endif
#endif
/*
*/
#if UART3_ENABLE
void UART3_IRQHandler()
{ 
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  uint32_t int_status = USART_STAT(UART3);
  usart_data_receive(UART3); //clear flag
  bool error = int_status & 0x07; //NERR, FERR or PERR
  
 if((int_status & 0x10)) { //IDLE interrupt for Rx end
    //DMA Rx
#if UART3_RX_DMA_ENABLE  
    uart3.dma_rx_end(error);  
    uart3.dma_rx_start();
#endif
    if(rx_irq_hook[3] != nullptr) {
      rx_irq_hook[3](rx_irq_hook_param[3], error);
    }
  }
  
  //Int Rx
#if !UART3_RX_DMA_ENABLE
  if((int_status & 0x20)) { //RBNE interrupt
    uart3.int_rx(error);
  }
#endif
  
  //Int Tx
#if !UART3_TX_DMA_ENABLE
  if((int_status & 0x80)) //TBE
  {
    if(uart3.int_tx() == 0) { //Tx end
      if(tx_irq_hook[3] != nullptr) {
        tx_irq_hook[3](tx_irq_hook_param[3], 0);
      }
    }
  }
#endif
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
/*
*/
#if UART3_TX_DMA_ENABLE
void UART3_TX_DMA_CH_IRQH()
{
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  if(dma_interrupt_flag_get(UART3_TX_DMA_PORT, UART3_TX_DMA_CH, DMA_INT_FLAG_FTF) != RESET)
  {
    dma_interrupt_flag_clear(UART3_TX_DMA_PORT, UART3_TX_DMA_CH, DMA_INT_FLAG_FTF);
    if(tx_irq_hook[3] != nullptr) {
      tx_irq_hook[3](tx_irq_hook_param[3], 0);
    }
    uart3.dma_tx_end();
    uart3.dma_tx_start();
  }
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
#endif
#endif
/*
*/
#if UART4_ENABLE
void UART4_IRQHandler()
{ 
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  uint32_t int_status = USART_STAT(UART4);
  usart_data_receive(UART4); //clear flag
  bool error = int_status & 0x07; //NERR, FERR or PERR
  
  if((int_status & 0x10)) { //IDLE interrupt for Rx end
    //DMA Rx
#if UART4_RX_DMA_ENABLE  
    uart4.dma_rx_end(error);  
    uart4.dma_rx_start();
#endif
    if(rx_irq_hook[4] != nullptr) {
      rx_irq_hook[4](rx_irq_hook_param[4], error);
    }
  }
  
  //Int Rx
#if !UART4_RX_DMA_ENABLE
  if((int_status & 0x20)) { //RBNE interrupt
    uart4.int_rx(error);
  }
#endif
  
  //Int Tx
#if !UART4_TX_DMA_ENABLE
  if((int_status & 0x80)) //TBE
  {
    if(uart4.int_tx() == 0) { //Tx end
      if(tx_irq_hook[4] != nullptr) {
        tx_irq_hook[4](tx_irq_hook_param[4], 0);
      }
    }
  }
#endif
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
/*
*/
#if UART4_TX_DMA_ENABLE
void UART4_TX_DMA_CH_IRQH()
{
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  if(dma_interrupt_flag_get(UART4_TX_DMA_PORT, UART4_TX_DMA_CH, DMA_INT_FLAG_FTF) != RESET)
  {
    dma_interrupt_flag_clear(UART4_TX_DMA_PORT, UART4_TX_DMA_CH, DMA_INT_FLAG_FTF);
    if(tx_irq_hook[4] != nullptr) {
      tx_irq_hook[4](tx_irq_hook_param[4], 0);
    }
    uart4.dma_tx_end();
    uart4.dma_tx_start();
  }
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
#endif
#endif

/*
*/
#ifdef __cplusplus
}
#endif

